package com.burukeyou.smartdi.register;

import com.burukeyou.smartdi.config.SpringBeanContext;
import com.burukeyou.smartdi.annotations.BeanAliasName;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

/**
 *
 BeanDefinitionRegistryPostProcessor 是 Spring 框架中的一个扩展接口，属于 Spring IoC 容器的扩展点。
 它允许开发者在 bean 定义阶段（即 Bean 实例化之前）对 BeanDefinition 进行动态修改或添加新的 Bean 定义

 注意事项
 1、触发顺序:
    a、BeanDefinitionRegistryPostProcessor 的方法 postProcessBeanDefinitionRegistry 会在 postProcessBeanFactory 之前执行。
    b、执行顺序大致为：
        postProcessBeanDefinitionRegistry() -> 加载 BeanDefinition -> postProcessBeanFactory() -> 实例化 Bean。
 2、与其他后置处理器的关系:
    它比普通的 BeanFactoryPostProcessor 更早执行，适合对 BeanDefinition 的操作。
    不会对已经实例化的 Bean 生效，只能操作 BeanDefinition。
 3、多实例顺序控制:
    多个 BeanDefinitionRegistryPostProcessor 的执行顺序可以通过 @Order 或实现 PriorityOrdered 接口控制。
 4、影响范围:
    postProcessBeanDefinitionRegistry 是容器全局的，只需注册一次即可影响所有 BeanDefinition。

 使用场景
 1、动态注册新的 Bean 定义: 可以在运行时动态向容器中注册 Bean。
 2、修改已有的 Bean 定义: 可以在 Bean 实例化之前修改其定义信息（例如：修改类名、设置默认属性等）。
 3、实现自定义注解的解析: 可扫描项目中的自定义注解，并将其注册为 Bean。
 4、整合外部框架: 动态加载外部框架的 Bean 定义。

 * @author  /
 */
@Component
public class ProxySPIAliasNameRegister implements BeanDefinitionRegistryPostProcessor {

    /**
     * 在 Spring 容器的 BeanDefinitionRegistry 中对所有已定义的 Bean 进行扫描，查找是否有被 @BeanAliasName 注解修饰的类，并注册其别名。
     * 如果类上存在 @BeanAliasName 注解，则将其值作为别名，调用 SpringBeanContext.registerBeanAlias 方法注册到容器中
     *
     * 触发时机: 在容器加载所有的 BeanDefinition 之后，实例化 Bean 之前。
     * 作用:
     *      提供一个钩子，用于在容器中动态注册新的 Bean 定义。
     *      可以移除或修改已有的 Bean 定义。
     * 参数:
     *      BeanDefinitionRegistry registry：用于管理 BeanDefinition 的注册表，可以通过它动态操作 Bean 定义。
     * @param registry /
     * @throws BeansException /
     */
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        // 获取容器中所有的 Bean 定义名称
        String[] beanDefinitionNames = registry.getBeanDefinitionNames();
        // 遍历每个 Bean 定义名称
        for (String beanDefinitionName : beanDefinitionNames) {
            // 从容器中获取该 Bean 定义对象
            BeanDefinition beanDefinition = registry.getBeanDefinition(beanDefinitionName);
            // 获取该 Bean 定义对应的类名
            String beanClassName = beanDefinition.getBeanClassName();
            // 如果类名为空，则跳过当前循环
            if (StringUtils.isEmpty(beanClassName)){
                continue;
            }
            try {
                // 加载该类的 Class 对象，是为了判断是否有BeanAliasName注解
                Class<?> beanClass = Class.forName(beanClassName);
                // 检查该类是否被 @BeanAliasName 注解标注
                BeanAliasName proxySPIName = beanClass.getAnnotation(BeanAliasName.class);
                // 如果存在 @BeanAliasName 注解，注册别名
                if (proxySPIName != null){
                    SpringBeanContext.registerBeanAlias(beanDefinitionName,proxySPIName.value());
                }
            } catch (ClassNotFoundException e) {
                // 如果找不到类，抛出异常并附上详细信息
                throw new RuntimeException("can not find class for beanDefinitionName " + beanDefinitionName,e);
            }
        }
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {


    }
}
